/* 
 * File:   sysfun.c
 * Author: apleilx
 *
 * Created on 2015年9月3日, 上午9:59
 */

#define _LICENSE_MODULE_
#include "bsp.h"
#include "license.h"
#include "par\par_tab.h"
#include "appcfg.h"
#include "mbcom.h"
#include "swap.h"
#include "str_ext.h"
#include "dataproc.h"
#include "des.h"

#ifndef LIC_FUN_EN
#define LIC_FUN_EN 0
#endif

extern const uint16_t iap_ase_key_src[];

void license_crc_dec(void);
void license_swap_dec(void);
void license_des_dec(void);

void lic_save(void);
void lic_read(void);

void license_open(uint32_t val);
void license_close(void);

/*****************************************************************************
* @brief   license check.
* @param   none
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
void license_check(void)
{
#if LIC_FUN_EN < 1
    lic_man.info.en = ~LIC_EN_FLAG;
#endif

    //开启加密
    if (sys_par.lic_req.uval / 100 == 55)
    {
        sys_par.lic_req.uval = 0;
        license_open(sys_par.lic_req.uval % 100);
    }

    //授权检查
    if (lic_man.info.en == LIC_EN_FLAG)
    {
        //剩余次数检测
        if (lic_man.info.val > 0)
            lic_man.b_ok = 1;
        else
            lic_man.b_ok = 0;

        //授权解锁验证
        if (lic_man.b_decode_req == LIC_DEC_MODE_CRC)
        {
            license_crc_dec();
            lic_man.b_decode_req = 0;
        }

        if (lic_man.b_decode_req == LIC_DEC_MODE_SWAP)
        {
            license_swap_dec();
            lic_man.b_decode_req = 0;
        }

        if (lic_man.b_decode_req == LIC_DEC_MODE_DES)
        {
            license_des_dec();
            lic_man.b_decode_req = 0;
        }
    }
    else
    {
        lic_man.b_ok = 1;
    }
}

/*****************************************************************************
* @brief   license decode req.        
* @param   none
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
void license_dec_req(uint8_t mode)
{
    lic_man.b_decode_req = mode;

    //授权解锁验证
    if (lic_man.info.en == LIC_EN_FLAG)
    {
        if (lic_man.b_decode_req == LIC_DEC_MODE_CRC)
        {
            license_crc_dec();
            lic_man.b_decode_req = 0;
        }

        if (lic_man.b_decode_req == LIC_DEC_MODE_SWAP)
        {
            license_swap_dec();
            lic_man.b_decode_req = 0;
        }

        if (lic_man.b_decode_req == LIC_DEC_MODE_DES)
        {
            license_des_dec();
            lic_man.b_decode_req = 0;
        }
    }
}

/*****************************************************************************
* @brief   license code cal.        
* @param   none
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
void license_crc_dec(void)
{
    uint16_t crc;
    UINT32_VAL code;

    code.word.LW = sys_par.lic_key1.uval;
    code.word.HW = sys_par.lic_key2.uval;

    code.word.LW = ~code.word.LW;
    code.word.HW = ~code.word.HW;

    crc = mb_crc(code.v, 4);

    code.word.LW -= crc;
    code.word.HW += crc;

    code.word.LW *= crc;
    code.word.HW *= crc;

    code.word.LW %= 9555;
    code.word.HW %= 9333;

    if (code.word.LW == 0)
        code.word.LW = 2458;
    if (code.word.HW == 0)
        code.word.HW = 1732;

    if ((sys_par.lic_inf1.uval == code.word.LW) && (sys_par.lic_inf2.uval == code.word.HW))
    {
        license_close();
        sys_par.lic_inf1.uval = 0;
        sys_par.lic_inf2.uval = 0;
    }
}

/*****************************************************************************
* @brief   license code cal.        
* @param   none
* @return  none
*****************************************************************************/
void license_swap_dec(void)
{
    uint8_t dat[10], key[10];
    lic_str_type lic;

    // 键值预处理
    copy_u8(&sys_par.lic_key1, key, 8);
    swap_bit_map_u8(key, key);
    map_add_u8(key, (uint8_t *)iap_ase_key_src, key, 8);
    swap_bit_map_u8(key, key);

    // 数据解码
    copy_u8(&sys_par.lic_inf1, dat, 8);
    swap_bit_map_u8(dat, dat);
    swap_u8_with_u4(dat, dat, 8);
    map_sub_u8(dat, key, dat, 8);
    swap_u8_with_u4(dat, dat, 8);
    swap_bit_map_u8(dat, dat);

    // 授权信息
    if (0 == mb_crc(dat, 8))
    {
        copy_u8(dat, &lic, 8);
        if ((lic.en == LIC_EN_FLAG) || ((lic.en == (uint16_t)(~LIC_EN_FLAG))))
        {
            copy_u8(&lic, &lic_man.info, 8);
        }
    }
}

/*****************************************************************************
* @brief   license code cal.        
* @param   none
* @return  none
*****************************************************************************/
void license_des_dec(void)
{
    uint8_t dat[10], key[10], out[10];
    lic_str_type lic;
    mbedtls_des_context enc;

    // 键值预处理
    copy_u8(&sys_par.lic_key1, key, 8);
    swap_bit_map_u8(key, key);
    map_add_u8(key, (uint8_t *)iap_ase_key_src, key, 8);
    swap_bit_map_u8(key, key);

    // 数据解码
    mbedtls_des_init(&enc);
    mbedtls_des_setkey_dec(&enc, key);

    copy_u8(&sys_par.lic_inf1, dat, 8);
    swap_bit_map_u8(dat, dat);
    swap_u8_with_u4(dat, dat, 8);
    mbedtls_des_crypt_ecb(&enc, dat, out);
    swap_u8_with_u4(out, dat, 8);
    swap_bit_map_u8(dat, dat);

    mbedtls_des_free(&enc);

    // 授权信息
    if (0 == mb_crc(dat, 8))
    {
        copy_u8(dat, &lic, 8);
        if ((lic.en == LIC_EN_FLAG) || ((lic.en == (uint16_t)(~LIC_EN_FLAG))))
        {
            copy_u8(&lic, &lic_man.info, 8);
        }
    }
}

/*****************************************************************************
*
* @brief   license open.
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void license_open(uint32_t val)
{
    //授权若未开启，打开授权功能
    if (lic_man.info.en != LIC_EN_FLAG)
    {
        lic_man.info.en = LIC_EN_FLAG;
        lic_man.info.val = val;

        //清除授权使用次数
        lic_save();

        //重启系统
        NVIC_SystemReset();
    }
}

/*****************************************************************************
* @brief   license open.       
* @param   none
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
void license_close(void)
{
    //授权开启，关闭授权功能
    if (lic_man.info.en == LIC_EN_FLAG)
    {
        lic_man.info.en = ~LIC_EN_FLAG;
        lic_man.info.val = 0;
        lic_save();
    }
}

/*****************************************************************************
* @brief   license time inc. 
* @param   none
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
void license_use_once(void)
{
    if (lic_man.info.en == LIC_EN_FLAG)
    {
        //使用次数递增
        if (lic_man.info.val > 0)
        {
            lic_man.info.val--;
            lic_save();
        }
    }
}

/*****************************************************************************
* @brief   license init.      
* @param   none
* @return  none
*****************************************************************************/
void license_init(void)
{
    //读取授权使用次数
    lic_read();

    //执行一次验证
    license_check();
}

/*****************************************************************************
* @brief   save and read.      
* @param   none
* @return  none
*****************************************************************************/
void lic_save(void)
{
    uint8_t dat[10];

    lic_man.info.crc = mb_crc((uint8_t *)(&lic_man.info), 6);

    copy_u8(&lic_man.info, dat, 8);
    map_add_u8(dat, (uint8_t *)iap_ase_key_src, dat, 8);
    swap_bit_map_u8(dat, dat);
    swap_u8_with_bit(dat, dat, 8);
    swap_u8_with_u4(dat, dat, 8);

    eep_save(EEP_LIC_BASE + 0, 8, dat);
    eep_save(EEP_LIC_BASE + 8, 8, dat);
}

void lic_read(void)
{
    uint8_t dat[10];
    uint16_t crc;

    // 读信息
    eep_read(EEP_LIC_BASE + 0, 8, dat);

    swap_u8_with_u4(dat, dat, 8);
    swap_u8_with_bit(dat, dat, 8);
    swap_bit_map_u8(dat, dat);
    map_sub_u8(dat, (uint8_t *)iap_ase_key_src, dat, 8);

    if (0 == mb_crc(dat, 8))
    {
        copy_u8(dat, &lic_man.info, 8);
        return;
    }

    // 读备份
    eep_read(EEP_LIC_BASE + 8, 8, dat);

    swap_u8_with_u4(dat, dat, 8);
    swap_u8_with_bit(dat, dat, 8);
    swap_bit_map_u8(dat, dat);
    map_sub_u8(dat, (uint8_t *)iap_ase_key_src, dat, 8);

    if (0 == mb_crc(dat, 8))
    {
        copy_u8(dat, &lic_man.info, 8);
        return;
    }

    // 均无效
    license_open(1);
}
